# -*- coding:utf-8 -*-

from __future__          import division

from configure           import config
from utils.routes        import route
from tornado.options     import options

from utils               import mongo
#from utils.urls          import get_image_url_by_size
from utils.cal           import getd
from utils.fastdfs_utils import DfsUtils
from utils.errors        import err_param
from service.file        import sync2qiniu
from loog.mylog          import flogger as logger
from configure.config    import DB_NAME, COLL_SEED, FILE_CDN_URL
from service.base        import AuthHandler

import tornado.web
import time, os


#@route(r'/file/upload/page', 'file_upload_page')
class UploadPageHandler(tornado.web.RequestHandler):
    """ 测试 - 上传文件页面 """

    def get(self):
        self.render('manage/upload.html')


@route(r'/web/comupload', 'comupload')
class ComUploaderHandler(AuthHandler):
    """ 通用上传 """

    db_name             = config.DB_NAME
    collection_name     = config.COLLECTION_DATAS

    db_files            = "files"
    collection_files    = "files"

    @tornado.web.asynchronous
    @tornado.gen.engine
    def post(self):
        """ 上传文件

        并同步到七牛
        """

        logger.info('Start To Parse File')

        file_name = self.get_argument('file.name', None)
        file_path = self.get_argument('file.path', None)
        file_md5 = self.get_argument('file.md5', None)
        file_size = self.get_argument('file.size', None)
        #file_ctype = self.get_argument('file.content_type', None)

        logger.error("arguments %s" %self.request.arguments)

        # 检查参数
        if not file_name or not file_md5 or not file_size or not file_path:
            self.write(err_param)
            self.finish()
            return

        # 检测文件后缀名
        file_ext = file_name.split(".")[-1]
        if file_ext != 'zip':
            logger.info("ERROR_wrong_file_ext")
            self.write({'code':406})
            self.finish()
            return

        # 校验文件名是否正确
        """
        ret, infos = yield tornado.gen.Task(self.check_filename, file_name)
        if not ret:
            self.write(err_param)
            self.finish()
            return
        """

        # 文件是否已存在  根据文件名和文件md5判断
        is_exists = yield tornado.gen.Task(
                            self.check_file_exist, file_name, file_md5)
        if is_exists:
            self.write({'code':90002})
            self.finish()
            return

        size = getd(float(file_size)/1024/1024)    # size in MB

        file_buffer = None
        length = os.path.getsize(file_path)
        with open(file_path, "r") as file_data:
            file_buffer = file_data.read(length)

        file_md5_ext = file_md5 + '_' + file_ext
        #file_url = get_image_url_by_size(file_md5, use_cdn=True, ext=file_ext)
        cdn_url = FILE_CDN_URL + '/'+file_md5_ext+'.'+file_ext

        logger.info('UPload to fastdfs and qiniu')
        try:
            file_id = options['fastdfs_client'].upload_by_buffer(
                                                    file_md5_ext,
                                                    file_buffer,
                                                    file_ext)
            if not file_id: raise ValueError('Fastdfs Error')

            logger.info('Done With Fastdsf')

            ret, info = yield tornado.gen.Task(
                                        self.save_file,
                                        file_id,
                                        file_md5_ext)
            sync2qiniu.sync(file_md5_ext)
            logger.info('Down with qiniu')
        except Exception, e:
            logger.exception(e)
            self.write({'code':500})
            self.finish()
            return

        self.write({
            'code':200,
            'data':{
                'md5'  :file_md5,
                'size' :size,
                'name' :file_name,
                'url'  :cdn_url,
                'bytes':file_size
            }
        })
        logger.info('Done Upload File')
        self.finish()
        return

        """
        logger.error(ret)
        logger.error(info)

        # 保存到数据库
        infos['md5']            = md5
        infos['info']           = change_logs   # 更新日志
        infos['size']           = size          # 文件大小
        infos['finger_point']   = finger_point  # 指纹
        infos['scope']          = 'test'        # 设置域为测试环境，待确定可用后人工转为正式域
        infos['device_scope']   = "1"           # 仅限白名单设备
        infos['status']         = '0'           # 0为未激活状态，1为激活状态
        infos['download_url']   = download_url  # 下载地址
        infos['update_success'] = 0             # 更新成功次数
        infos['update_failed']  = 0             # 更新失败次数
        ret, info = yield tornado.gen.Task(self.save_2_mongo, infos)
        if ret:
            self.finish({'code': 0, 'info': info})
        else:
            self.finish({'code': 4, 'info': info})
        """

    @tornado.gen.engine
    def _check_and_upload(self, callback=None):
        """ 没有使用 """

        dfsUtils = DfsUtils()
        file_exists = False
        err_state = None

        self.file_md5 = self.file_md5 + "_" + self.ext
        self.qn_key = self.file_md5 + "." + self.ext
        self.file_id = yield tornado.gen.Task(dfsUtils.check_file_exists,
                                              self.file_md5)
        logger.error('file_id_first: %s' % self.file_id)
        if self.file_id:
            logger.info("find %s exists, write_result" % self.file_id)
            file_exists = True
            if callback:
                callback(file_exists, err_state)
            return

        length = os.path.getsize(self.file_path)
        with open(self.file_path, "r") as file_data:
            self.binary_content = file_data.read(length)
        self.file_id = options['fastdfs_client'].upload_by_buffer(
            self.file_md5,
            self.binary_content,
            self.ext
        )
        logger.info('file_id: %s' % self.file_id)
        if not self.file_id:
            logger.error('fastdfs_client error ')
            err_state = "upload error"
        else:
            pass
            #self.insert_file()
        if callback:
            callback(file_exists, err_state)

    @tornado.gen.engine
    def check_filename(self, filename, callback):
        """ 校验文件名格式是否正确 DROP """

        l = filename[:-4].split('_')
        if len(l) != 4 or '' in l:
            callback((False, 'file name error 1!'))
            return
        sn_ids_str, ver_from, ver, create_time = l[0], l[1], l[2], l[3]

        sn_ids = sn_ids_str.split(',')
        if '' in sn_ids:
            callback((False, 'sn ids error!'))
            return
        try:
            # if int(ver_from.replace('.','')) >= int(ver.replace('.','')):
            #     callback((False, 'ver error!'))
            #     return
            if compareversion(ver_from, ver) >= 0:
                callback((False, 'ver error!'))
                return
        except:
            callback((False, 'ver error!'))
            return

        infos = {
            'filename':     filename,           # 文件名
            'sn_ids':       sn_ids,             # 包含的sn ids
            'sn_ids_str':   sn_ids_str,
            'ver_from':     ver_from,           # 上一个版本的版本号
            'ver':          ver,                # 版本号
            'create_time':  create_time,        # 创建包的时间
            'ts':           int(time.time()),   # 时间戳
        }
        callback((True, infos))

    @tornado.gen.engine
    def check_file_exist(self, filename, md5, callback):
        """ 根据文件md5来查询，是否已经存在此zip包

        检查:
            1. 检查文件数据库
            2. 检查fota数据库
        """

        # 检查文件数据库
        query = {"md5":md5+'_zip'}
        r = yield tornado.gen.Task(
                mongo.find_one, self.db_files, self.collection_files, query)
        if r: callback(True)

        # 检查fota数据库
        spec = {
            '$or': [
                    {'md5':md5},
                    {'filename':filename}
               ]
        }
        res = yield tornado.gen.Task(mongo.find_one, DB_NAME, COLL_SEED, spec)
        if res: callback(True)
        callback(False)

    @tornado.gen.engine
    def save_2_mongo(self, infos, callback):
        """ 保存数据到mongodb
        """
        d = yield tornado.gen.Task(mongo.insert, config.DB_NAME, config.COLLECTION_DATAS, infos)
        if d:
            callback((True, 'save success!'))
        else:
            callback((False, 'save failed!'))

    @tornado.gen.engine
    def save_file(self, file_id, file_md5, callback):
        """ 保存数据到mongodb """

        file_data = {
            "file_id" : file_id,
            "md5"     : file_md5
        }
        d = yield tornado.gen.Task(mongo.insert, self.db_files, self.collection_files, file_data)
        if d:
            callback((True, 'save success!'))
        else:
            callback((False, 'save failed!'))


@route('/file/upload', 'file.upload')
class UploadFileHandler(tornado.web.RequestHandler):
    """ v1.0 版本使用的上传类 """

    db_name             = config.DB_NAME
    collection_name     = config.COLLECTION_DATAS

    db_files            = "files"
    collection_files    = "files"

    def get(self):
        self.finish('not implement.')

    @tornado.web.asynchronous
    @tornado.gen.engine
    def post(self):
        """ 上传文件
        * 返回值里code含义：    0 - 成功； 1 - 参数错误； 2 - 文件名格式出错； 3 - 文件已存在；　４－保存数据失败；
        """
        if not self.request.body:
            self.finish({'code': 1, 'info': 'params error!'})
            return

        # datas = json.loads(self.request.body)
        # filename = datas.get('filename', None)
        # size = datas.get('size', None)
        # md5 = datas.get('md5', None)
        # change_logs = datas.get('change_logs', None)
        # finger_point = datas.get('finger_point', None)
        # download_url = datas.get('download_url', None)
        # file_buffer  = datas.get('file_buffer', None)
        filename = self.get_argument('filename', None)
        size = self.get_argument('size', None)
        md5 = self.get_argument('md5', None)
        change_logs = self.get_argument('change_logs', None)
        finger_point = self.get_argument('finger_point', None)
        download_url = self.get_argument('download_url', None)
        # file_buffer  = self.get_argument('file_buffer', None)
        file_buffer = self.get_argument('file', None)
        logger.error("arguments %s" %self.request.arguments)

        # logger.info('body =', self.request.body, caller=self)
        logger.info('filename =', filename, 'size =', size, 'md5 =', md5,
                    'change_logs =', change_logs, 'finger_point =', finger_point,
                    'download_url =', download_url, caller=self)
        # 检查参数
        if not filename or not md5 or not change_logs or not finger_point or not download_url or not file_buffer:
            self.finish({'code': 1, 'info': 'params error!'})
            return

        # 校验文件名是否正确
        ret, infos = yield tornado.gen.Task(self.check_filename, filename)
        if not ret:
            self.finish({'code': 2, 'info': infos})
            return

        # 校验文件是否已经存在数据库了
        ret, info = yield tornado.gen.Task(self.check_file_exist, infos, md5)
        if ret:
            self.finish({'code': 3, 'info': info})
            return

        file_ext = filename.split(".")[-1]
        file_id = options['fastdfs_client'].upload_by_buffer(md5, file_buffer, file_ext)
        if not file_id:
            logger.error("fastdfs error")
            self.finish({'code': 5, 'info': ''})
            return
        logger.error("file_id %s" % file_id)

        ret, info = yield tornado.gen.Task(self.save_file, file_id, md5)
        logger.error(ret)
        logger.error(info)

        # 保存到数据库
        infos['md5']            = md5
        infos['info']           = change_logs   # 更新日志
        infos['size']           = size          # 文件大小
        infos['finger_point']   = finger_point  # 指纹
        infos['scope']          = 'test'        # 设置域为测试环境，待确定可用后人工转为正式域
        infos['device_scope']   = "1"           # 仅限白名单设备
        infos['status']         = '0'           # 0为未激活状态，1为激活状态
        infos['download_url']   = download_url  # 下载地址
        infos['update_success'] = 0             # 更新成功次数
        infos['update_failed']  = 0             # 更新失败次数
        ret, info = yield tornado.gen.Task(self.save_2_mongo, infos)
        if ret:
            self.finish({'code': 0, 'info': info})
        else:
            self.finish({'code': 4, 'info': info})

    @tornado.gen.engine
    def check_filename(self, filename, callback):
        """ 校验文件名格式是否正确
        """
        l = filename[:-4].split('_')
        if len(l) != 4 or '' in l:
            callback((False, 'file name error 1!'))
            return
        sn_ids_str, ver_from, ver, create_time = l[0], l[1], l[2], l[3]

        sn_ids = sn_ids_str.split(',')
        if '' in sn_ids:
            callback((False, 'sn ids error!'))
            return
        try:
            # if int(ver_from.replace('.','')) >= int(ver.replace('.','')):
            #     callback((False, 'ver error!'))
            #     return
            if compareversion(ver_from, ver) >= 0:
                callback((False, 'ver error!'))
                return
        except:
            callback((False, 'ver error!'))
            return

        infos = {
            'filename':     filename,           # 文件名
            'sn_ids':       sn_ids,             # 包含的sn ids
            'sn_ids_str':   sn_ids_str,
            'ver_from':     ver_from,           # 上一个版本的版本号
            'ver':          ver,                # 版本号
            'create_time':  create_time,        # 创建包的时间
            'ts':           int(time.time()),   # 时间戳
        }
        callback((True, infos))

    @tornado.gen.engine
    def check_file_exist(self, infos, md5, callback):
        """ 根据文件md5来查询，是否已经存在此zip包
        """
        spec = {
                '$or': [
                        {
                            'md5':          md5
                        },
                        {
                            'filename':     infos['filename']
                        }
                       ]
                }
        d = yield tornado.gen.Task(mongo.find_one, config.DB_NAME, config.COLLECTION_DATAS, spec)
        logger.info('d =', d, caller=self)
        if d:
            callback((True, 'file exists!'))
        else:
            callback((False, 'ok'))

    @tornado.gen.engine
    def save_2_mongo(self, infos, callback):
        """ 保存数据到mongodb
        """
        d = yield tornado.gen.Task(mongo.insert, config.DB_NAME, config.COLLECTION_DATAS, infos)
        if d:
            callback((True, 'save success!'))
        else:
            callback((False, 'save failed!'))

    @tornado.gen.engine
    def save_file(self, file_id, file_md5, callback):
        """ 保存数据到mongodb
        """
        file_data = {
            "file_id" : file_id,
            "md5"     : file_md5
        }
        d = yield tornado.gen.Task(mongo.insert, self.db_files, self.collection_files, file_data)
        if d:
            callback((True, 'save success!'))
        else:
            callback((False, 'save failed!'))


def compareversion(version1, version2):
    i = 0
    result = 0

    version1_strs = version1.split(".")
    version2_strs = version2.split(".")

    while (i < 4 and not result):
        pos_result =  cmp(int(version1_strs[i]), int(version2_strs[i]))
        if pos_result:
            result = pos_result
        else:
            i += 1

    return result

# if __name__ == '__main__':
#     r = [{'ver':"0.7.1.10"}, {'ver':"0.7.1.0"}]
#     r.sort(lambda x,y:compareversion(x['ver'],y['ver']))
#     print r
